package com.game.core.dbcs.executor;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.game.core.dbcs.DBCS;
import com.game.core.dbcs.daoproxy.DaoExecutorProxyEntrance;
import com.game.core.dbcs.daoproxy.IDaoExecutor;
import com.game.core.dbcs.dbspace.DBSpace;
import com.game.core.dbcs.dbspace.DBZone;

/**
 * DAO接口执行代理 对应Mapper，跟一组数据库操作接对应
 * @author
 */
public class ExecutorProxy
{
	private static final Logger logger = LoggerFactory.getLogger(ExecutorProxy.class);

	private static final String TRANSACTION_FLAG = "Transaction";
	private static final String START_TRANSACTION_FLAG = "startTransaction";
	private static final String COMMIT_TRANSACTION_FLAG = "commitTransaction";
	private static final String END_TRANSACTION_FLAG = "endTransaction";

	private String beanName;
	private Class<? extends IDaoExecutor> excutorInterface;
	private Map<String, StatementProxy> statementMap;// method名称与实现的对应
	private IDaoExecutor daoExcutor;
	private boolean available;
	private String sqlMapXMLPath;

	public ExecutorProxy(String beanName,String sqlMapXMLPath)
	{
		this.beanName = beanName;
		this.sqlMapXMLPath=sqlMapXMLPath;
		statementMap = new HashMap<String, StatementProxy>();
	}

	public void initialize(Class<? extends IDaoExecutor> interfaceClass)
	{
		if (interfaceClass == null)
			return;

		if (!IDaoExecutor.class.isAssignableFrom(interfaceClass))
		{
			logger.error("executor of " + this.beanName + "[" + interfaceClass.getName() + "]  need inherit IDaoExecutor interface");
			return;
		}

		String tmpClassName = interfaceClass.getSimpleName();
		Method[] tmpMethods = interfaceClass.getMethods();
		DAOInfo tmpDAOInfo;
		StatementProxy tmpStatementProxy;
		DaoFunctionAnnotation functionAnnotation;
		for (Method tmpMethod : tmpMethods) 
		{
			tmpDAOInfo = (DAOInfo) tmpMethod.getAnnotation(DAOInfo.class);
			if (tmpDAOInfo != null)
			{
				functionAnnotation = new DaoFunctionAnnotation(tmpClassName + "." + tmpMethod.getName(), tmpDAOInfo.Params(), tmpMethod.getParameterTypes());
				if (functionAnnotation.isValid())
				{
					tmpStatementProxy = new StatementProxy(beanName, tmpMethod, functionAnnotation,sqlMapXMLPath);
					statementMap.put(tmpMethod.getName(), tmpStatementProxy);
				}
				else
				{
					logger.error(this.beanName + "." + tmpMethod.getName() + ": method annotation is invalid");
				}
			}
			else
			{
				if (!tmpMethod.getName().contains(TRANSACTION_FLAG))
					logger.error(this.beanName + "." + tmpMethod.getName() + ": method annotation not exist");
			}
		}

		this.excutorInterface = interfaceClass;
		// Class<?> clazzProxy = Proxy.getProxyClass(
		// excutorInterface.getClassLoader(), excutorInterface);
		try
		{
			daoExcutor = (IDaoExecutor) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[] { interfaceClass }, new DaoExecutorProxyEntrance(this));
			// Constructor<?> excutorProxyConstructor = clazzProxy
			// .getConstructor(InvocationHandler.class);
			// daoExcutor = (IDaoExecutor) excutorProxyConstructor
			// .newInstance(new DaoExecutorProxyEntrance(this));
			available = true;
		}
		catch (Exception e)
		{
//			e.printStackTrace();
			logger.error("failed init executorProxy,",e);
		}
	}

	public void regStatementProxy(StatementProxy statementProxy)
	{
		statementMap.put(statementProxy.getMethodName(), statementProxy);
	}

	public Object invokeStatement(String methodname, Object[] args)
	{
		if (!available)
		{
			logger.error("executor of " + this.beanName + " is invalid");
			return null;
		}

		DBZone dbzone = DBSpace.getDBZone(sqlMapXMLPath);
		try
		{
			if (START_TRANSACTION_FLAG.equals(methodname))
			{
				if (dbzone != null)
					dbzone.startTransaction();
				return true;
			}
			else if (COMMIT_TRANSACTION_FLAG.equals(methodname))
			{
				if (dbzone != null)
					dbzone.commitTransaction();
				return true;
			}
			else if (END_TRANSACTION_FLAG.equals(methodname))
			{
				if (dbzone != null)
					dbzone.endTransaction();
				return true;
			}
		}
		catch (Exception e)
		{
//			e.printStackTrace();
			logger.error("invokeStatement error",e);
			return null;
		}

		StatementProxy tmpStatementProxy = statementMap.get(methodname);
		if (tmpStatementProxy == null)
		{
			logger.error("executor " + methodname + " of " + this.beanName + " not exist");
			return null;
		}

		if (DBCS.getIntereptor() != null)
			DBCS.getIntereptor().before(tmpStatementProxy.getStatementId(), args);

		Object result = null;
		try
		{
			result = tmpStatementProxy.invoke(args);
		}
		catch (Exception e)
		{
			logger.error("invokeStatement", e);
		}
		finally
		{
			if (DBCS.getIntereptor() != null)
				DBCS.getIntereptor().after(tmpStatementProxy.getStatementId(), args, result);
		}
		return result;
	}

	public IDaoExecutor getExecutor()
	{
		return this.daoExcutor;
	}

	public boolean isAvailable()
	{
		return available;
	}

	public Class<? extends IDaoExecutor> getExcutorInterface()
	{
		return excutorInterface;
	}

	public String getExcutorInterfaceName()
	{
		return (excutorInterface != null) ? excutorInterface.getSimpleName() : null;
	}
	
	public String getSqlMapXMLPath() {
		return sqlMapXMLPath;
	}

	public void setSqlMapXMLPath(String sqlMapXMLPath) {
		this.sqlMapXMLPath = sqlMapXMLPath;
	}

}
